/*!
 * vinculum
 * Copyright(c) 2017 azzly
 * MIT Licensed
 */
 
'use strict';

/**
 * Module dependencies.
 * @private
 */
const helper = require("../helper");
const CONST = require("../CONST");
const config = require("../config");
const debug = require("../debug")(__filename);
const datasource = require("../datasource");
const error = require("../HTTPErrors");
const cache = require('../cache');
 
/**
 * class.
 */

class service{
  constructor(service_name){
    this.service_name = service_name;
  }

  invoke(...args){
    let _this = this;
    let len = args.length;
    let params = {};
    if(len === 1){
      if(typeof args[0] === 'string' || typeof args[0] === 'number'){
				params = [args[0]];
      }else{
        params = args[0] || {};
      }
    }else if(len > 1){
      params = args;
    }
    return new Promise((resolve, reject)=>{
      if(!_this.service_name){
        reject(error.NOT_FOUND_SERVICE_NAME);
      }else{
        service.find(_this.service_name).then(info=>{
					if(info.disabled === CONST.DISABLED_TYPES.DISABLED){
						reject(error.GONE);
					}else{
						let data = [];
						let service_id = info.id;
						let service_main_sql = info.main;
						let service_params = info.param_list;
						let insert_result = {};
						let paramsIsArray = Array.isArray(params);
						let paramsname = 0;
						for(let {name,type='form'} of service_params){
							let value = null;
							if(type === 'md5'){
									value = helper.md5(params[paramsIsArray?paramsname++:name]);
							}else if(type === 'sha1'){
									value = helper.sha1(params[paramsIsArray?paramsname++:name]);
							}else if(type === 'key'){
									value = helper.uuid();
							}else if(type === 'form'){
									value = params[paramsIsArray?paramsname++:name];
							}else{
									value = params[paramsIsArray?paramsname++:`__${type}__${name}`];
							}
							value = helper.json2string(value);
							if(value === '') value = null;
							insert_result[name] = value;
							data.push(value);
						}

						if(info.type === CONST.SERVICE_TYPES.SELECT 
							&& CONST.REG.NUMBER.test(params.__limit_no__) 
							&& CONST.REG.NUMBER.test(params.__limit_size__)){
							service_main_sql = `select * from (${service_main_sql}) limittmpname limit ?,?`;
							data.push(parseInt(params.__limit_no__));
							data.push(parseInt(params.__limit_size__));
						}
						
						if(info.type === CONST.SERVICE_TYPES.SELECT 
							&& params.__get_allcount__ === '1'){
							service_main_sql = `select count(*) as allcount from (${service_main_sql}) allcounttmpname`;
						}
						
						datasource.getDB(info.datasourceid).query(service_main_sql,data).then(result=>{
							debug(`excute sql: ',${service_main_sql},'\nsql data: ${data}`);
							if(info.type === CONST.SERVICE_TYPES.SELECT){
								resolve(result);
							}else{
								insert_result.affectedRows = result.affectedRows;
								insert_result.insertId = result.insertId;
								insert_result.changedRows = result.changedRows;
								resolve(insert_result);
							}
						}).catch(err=>{
							reject(err);
						});
					}
        }).catch(err=>{
          reject(err);
        });
      }
    });
  }

  static find(service_name){
    return new Promise((resolve, reject)=>{
      if(!service_name) return reject(error.NOT_FOUND_SERVICE_NAME);
			
			if(CONST.SERVICES[service_name]){
        resolve(CONST.SERVICES[service_name]);
        return;
      }
			
      let info = cache.getService(service_name);
      if(info){
        resolve(info);
      }else{
        datasource.systemQuery(CONST.SQLS.service_browse,[service_name,service_name]).then(result=>{
          info = result[0];
          if(info){
            datasource.systemQuery(CONST.SQLS.service_param_browse,[info.id]).then(result=>{
              info.param_list = result;
              cache.setService(service_name,info);
              resolve(info);
            }).catch(err=>{
              reject(err);
            });
          }else{
            reject(error.NOT_FOUND_SERVICE_NAME);
          }
        }).catch(err=>{
          reject(err);
        });
      }
    });
  }
}
module.exports = service;